package com.google.code.coma.loadbalancer;

import com.google.code.coma.domain.Part;
import com.google.code.coma.domain.Type;
import com.google.code.coma.loadbalancer.entity.FactoryTypeAmount;
import com.google.code.coma.loadbalancer.entity.Transfer;
import com.google.code.coma.loadbalancer.sd.FactorySupplyDemand;
import com.google.code.coma.loadbalancer.sd.FactorySupplyDemandFactory;

import java.util.*;

/**
 */
public abstract class LoadBalancer implements Runnable {
    private Comparator<FactoryTypeAmount> factoryTypeAmountComparator = new Comparator<FactoryTypeAmount>() {
        @Override
        public int compare(FactoryTypeAmount o1, FactoryTypeAmount o2) {
            return o1.getAmount() - o2.getAmount();
        }
    };

    protected Transfer getLoadBalanceTransfers(Map<String, List<Part>> factoriesParts) {
        List<FactoryTypeAmount> allSupplies = new ArrayList<FactoryTypeAmount>();

        Map<Type, List<FactoryTypeAmount>> allDemandsMap = new HashMap<Type, List<FactoryTypeAmount>>();

        for (Map.Entry<String, List<Part>> entry : factoriesParts.entrySet()) {
            FactorySupplyDemand factorySupplyDemand = FactorySupplyDemandFactory.createSupplyDemand(entry.getKey(), entry.getValue());
            handleFactorySupplyDemand(factorySupplyDemand, allSupplies, allDemandsMap);
        }

        Collections.sort(allSupplies, factoryTypeAmountComparator);

        for (List<FactoryTypeAmount> demandList : allDemandsMap.values()) {
            Collections.sort(demandList, factoryTypeAmountComparator);
        }

        for (FactoryTypeAmount supply : allSupplies) {
            if (supply.getAmount() == 0) {
                return null;
            }

            Type type = supply.getType();
            List<FactoryTypeAmount> allDemands = allDemandsMap.get(type);

            if (allDemands != null) {
                for (FactoryTypeAmount demand : allDemands) {
                    if (demand.getAmount() > 0) {
                        return new Transfer(supply, demand);
                    }
                }
            }
        }

        return null;
    }

    private void handleFactorySupplyDemand(FactorySupplyDemand factorySupplyDemand, List<FactoryTypeAmount> allSupplies, Map<Type, List<FactoryTypeAmount>> allDemandsMap) {
        allSupplies.addAll(factorySupplyDemand.getSupply());

        for (FactoryTypeAmount demand : factorySupplyDemand.getDemand()) {
            List<FactoryTypeAmount> addList = allDemandsMap.get(demand.getType());

            if (addList == null) {
                addList = new ArrayList<FactoryTypeAmount>();
                allDemandsMap.put(demand.getType(), addList);
            }

            addList.add(demand);
        }
    }
}
